const path = require('path')
// 相对路径改绝对路径
const pathResolve = pathStr => path.resolve(__dirname, pathStr)
// 创建html文件
const HtmlWebpackPlugin = require('html-webpack-plugin')
// css 文件抽离
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
// css 压缩
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin')
// js 压缩
const TerserWebpackPlugin = require('terser-webpack-plugin')
// eslint
const EslintWebpackPlugin = require('eslint-webpack-plugin')
// React 局部热更新
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
// 开发环境
const isDevelopment = process.env.NODE_ENV !== 'production';


// 样式处理公共方法
const getStyleLoader = (module, preset) => {
    return [
        isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader,
        {
            loader: 'css-loader',
            // css 模块化处理
            options: module ? {
                importLoaders: 1,
                modules: {
                    localIdentName: '[local]__[hash:10]'
                }
            } : {}
        },
        // css 兼容处理，配合 package.json 中 broserslist 指定兼容性
        {
            loader: 'postcss-loader',
            options: {
                postcssOptions: {
                    plugins: ['postcss-preset-env']
                }
            }
        },
        preset
    ].filter(Boolean)
}

module.exports = {
    entry: pathResolve('src/index.js'),
    output: {
        // 打包路径
        path: isDevelopment ? pathResolve('dist') : undefined,
        // 主入口命名
        filename: isDevelopment ? 'static/js/[name].js' : 'static/js/[name]_[hash:8].js',
        // js分割文件输出路径
        chunkFilename: isDevelopment ? 'static/js/[name]_chunk.js' : 'static/js/[name]_chunk_[hash:8].js',
        // 静态资源输出地址
        assetModuleFilename: 'static/file/[name]_[hash:8][ext]',
        // 清除上一次打包记录
        clean: true
    },
    module: {
        rules: [
            {
                // 每个文件只能被其中一个 loader 处理
                oneOf: [
                    // 样式处理
                    {
                        test: /\.css$/,
                        exclude: [/node_modules/, /\.module.css$/],
                        use: getStyleLoader(false)
                    },
                    {
                        test: /\.module.css$/,
                        exclude: [/node_modules/],
                        use: getStyleLoader(true)
                    },
                    {
                        test: /\.less$/,
                        exclude: [/node_modules/, /\.module.less$/],
                        use: getStyleLoader(false, 'less-loader')
                    },
                    {
                        test: /\.module.less$/,
                        exclude: [/node_modules/],
                        use: getStyleLoader(true, 'less-loader')
                    },
                    // 图片处理
                    {
                        test: /\.(png|svg|jpe?g|gif)$/,
                        type: 'asset',
                        parser: {
                            // 小于10kb 图片被转成 base64
                            dataUrlCondition: {
                                maxSize: 20 * 1024
                            }
                        },
                        generator: {
                            // 图片输出路径
                            filename: 'static/img/[name]_[hash:6][ext]'
                        }
                    },
                    // icon图标处理
                    {
                        test: /\.(ttf|woff2?)$/,
                        type: 'asset/resource',
                        generator: {
                            // 文件输出路径
                            filename: 'static/font/[name]_[hash:6][ext]'
                        }
                    },
                    // js\jsx 处理
                    {
                        test: /\.[tj]sx?$/,
                        include: pathResolve('src'),
                        loader: 'babel-loader',
                        options: {
                            // 开启 babel 缓存
                            cacheDirectory: true,
                            // 关闭缓存文件压缩
                            cacheCompression: false,
                            // 激活js的HMR
                            plugins: [isDevelopment && 'react-refresh/babel'].filter(Boolean)
                        }
                    }
                ]
            }
        ]
    },
    // 解析模块加载选项
    resolve: {
        // 自动补全文件扩展名
        extensions: ['.jsx', '.js', 'tsx', 'ts'],
        // 设置根路径
        alias: {
            '@': pathResolve('src')
        }
    },
    plugins: [
        // 创建 HTML
        new HtmlWebpackPlugin({
            // HTML 标题
            title: 'react app',
            // HTML 文件
            filename: 'index.html',
            // HTML 来源
            template: pathResolve('public/index.html'),
            // HTML ico图标
            favicon: pathResolve('public/favicon.ico'),
            // Script 插入位置
            inject: 'body'
        }),
        // css 文件抽离
        !isDevelopment && new MiniCssExtractPlugin({
            filename: 'static/css/[name].css',
            chunkFilename: 'static/css/[name]_chunk.css'
        }),
        // eslint配置
        new EslintWebpackPlugin({
            // 检测文件
            // 创建 eslintrc.js 文件
            context: pathResolve('src'),
            exclude: 'node_modules',
            // 开启缓存
            cache: true,
            // 缓存目录
            cacheLocation: pathResolve('node_modules/.cache/eslint')
        }),
        isDevelopment && new ReactRefreshWebpackPlugin()
    ].filter(Boolean),
    optimization: {
        // 是否压缩
        minimize: !isDevelopment,
        minimizer: [
            // css 压缩
            new CssMinimizerWebpackPlugin(),
            // js 压缩
            new TerserWebpackPlugin()
        ].filter(Boolean),
        // 代码分割配置
        splitChunks: {
            chunks: 'all',
            cacheGroups: {
                // react react-dom react-router-dom 打包一起
                react: {
                    test: /[\\/]node_modules[\\/]react(.*)?[\\/]/,
                    name: 'react_chunk',
                    priority: 40
                },
                // antd 单独打包
                antd: {
                    test: /[\\/]node_modules[\\/]antd[\\/]/,
                    name: 'antd_chunk',
                    priority: 30
                },
                // 剩余 node_modules 单独打包
                antd: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'libs_chunk',
                    priority: 20
                }
            }
        },
        // 文件名提取，避免引入导致重复编译
        runtimeChunk: {
            name: entrypoint => `${entrypoint.name}_runtime.js`
        }
    },
    // 构建错误提示
    devtool: isDevelopment ? 'cheap-module-source-map' : 'source-map',
    // 环境
    mode: isDevelopment ? 'development' : 'production',
    // 关闭性能风险，提升构建速度
    performance: false,
    devServer: {
        // 服务器访问目录
        static: pathResolve('dist'),
        // 服务器访问地址
        host: 'localhost',
        // 服务器端口
        port: 8080,
        // 默认打开页面
        open: true,
        // 热更新
        hot: true,
        // 压缩打包后的内容
        compress: true,
        // 解决前端路由刷新404问题
        historyApiFallback: true,
        // 浏览器端显示
        client: {
            // 编译错误
            overlay: true,
            // 编译进度
            progress: false
        },
        // 服务器代理请求
        proxy: {
            // 请求：/api/user
            // 代理：http://localhost:3000/user
            '/api': {
                // 后端服务器访问地址
                target: 'http://localhost:3000',
                // 不希望传递/api, 路径重写
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    }
}